using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using System.IO;
using DevExpress.XtraTreeList.Nodes;

namespace ProgNetComponentsDx.Controls.Editors
{
    public partial class OpenFileDlg : DevExpress.XtraEditors.XtraForm
    {
        private string _RootName;
        public bool CheckFileExists { get; set; }
        public bool CheckPathExists { get; set; }
        public string DefaultExt { get; set; }
        public string Filter { get; set; }
        public string InitialDirectory { get; set; }
        public bool Multiselect { get; set; }
        public string FileName { get; set; }

        public string RootDir { get; set; }
        public string RootName
        {
            get
            {
                if (_RootName.IsNull())
                    _RootName = "ROOT";
                return _RootName;
            }
            set
            {
                if (value.IsNotNull())
                {
                    _RootName = value;

                    lblRootName.Text = RootName + ":";
                }
                else
                    throw new Exception("RootName can't be empty!");
            }
        }
        public string Title
        {
            get { return Text; }
            set { Text = value; }
        }
        private Dictionary<string, int> Icons;

        public OpenFileDlg()
        {
            InitializeComponent();
            Icons = new Dictionary<string, int>();
        }

        private void OpenFileDlg_Load(object sender, EventArgs e)
        {
            cbMask.Properties.Items.Clear();
            lblRootName.Text = RootName + ":";
            lblRoot.Text = RootDir;

            if (Filter.IsNotNull())
            {
                string[] masks = Filter.AsString().Split('|');
                List<string> Mmasks = new List<string>();
                for (int i = 0; i < masks.Length; i = i + 2)
                {
                    cbMask.Properties.Items.Add(masks[i] + " (" + masks[i + 1] + ")");
                    Mmasks.Add(masks[i + 1]);
                }

                if (cbMask.Properties.Items.Count > 0)
                {
                    if (FileName.IsNotNull())
                    {
                        string m = Path.GetExtension(FileName);
                        cbMask.SelectedIndex = Mmasks.IndexOf("*" + m);
                        if (cbMask.SelectedIndex < 0)
                            cbMask.SelectedIndex = 0;
                    }
                    else
                        cbMask.SelectedIndex = 0;
                }
            }
            treeList1.Nodes.Clear();
            if (RootDir.IsNull())
                InitDrives();
            else
            {
                TreeListNode n = treeList1.AppendNode(new object[] { RootDir, new DirectoryInfo(RootDir).Name, "<Folder>" }, null);
                n.ImageIndex = GetFolderImage();
                n.Tag = true;
                n.HasChildren = DirHasChildren(RootDir);
                InitFiles(n);
            }
            if (FileName.IsNull())
                SelectFile(InitialDirectory);
            else
                SelectFile(FileName);
        }
        private string getFileFilter()
        {
            string filter = "*.*";
            if (Filter.IsNotNull())
            {
                string tmp =  cbMask.SelectedItem.AsString();
                filter = tmp.Substring(tmp.LastIndexOf('(') + 1).TrimEnd(')');
            }
            return filter;
        }

        private void InitFiles(TreeListNode node)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<TreeListNode>(this.InitFiles), node);
            }
            else
            {
                try
                {
                    treeList1.LockReloadNodes();
                    string ff = getFileFilter();
                    List<TreeListNode> nodes = new List<TreeListNode>();
                    foreach (TreeListNode nn in node.Nodes)
                    {
                        if (nn[colExtensions].AsString() != "<Drive>" &&
                                nn[colExtensions].AsString() != "<Folder>")
                        {
                            nodes.Add(nn);
                        }
                    }
                    foreach (TreeListNode n2 in nodes)
                    {
                        node.Nodes.Remove(n2);
                    }
                    nodes = null;

                    string[] files = Directory.GetFiles(node[this.colPath].AsString(), ff, SearchOption.TopDirectoryOnly);
                    {
                        foreach (string f in files)
                        {
                            try
                            {
                                TreeListNode n = treeList1.AppendNode(new object[] { f, Path.GetFileNameWithoutExtension(f), Path.GetExtension(f).TrimStart('.') }, node);
                                n.ImageIndex = GetFileImage(f);
                                n.Tag = true;
                                n.HasChildren = false;
                            }
                            catch { }
                        }
                    }
                }
                catch { }
                finally
                {
                    treeList1.UnlockReloadNodes();
                }
            }
        }
        private void InitDrives()
        {
            TreeListNode node;
            try
            {
                string[] root = Directory.GetLogicalDrives();
                foreach (string s in root)
                {
                    node = treeList1.AppendNode(new object[] { s, s, "<Drive>" }, null);
                    System.IO.DriveInfo di = new System.IO.DriveInfo(s);
                    if (di.IsReady)
                    {
                        node.HasChildren = DirHasChildren(s);
                    }
                    node.ImageIndex = GetDriveImage(s);
                    node.Tag = true;
                    InitFiles(node);
                }
            }
            catch { }
        }

        private int GetDriveImage(string path)
        {
            int index = -1;
            if (!Icons.ContainsKey("<Drive>"))
            {
                Icon i = Shell32.GetFileIcon(path, Shell32.IconSize.Small, true);
                imageList1.Images.Add(i.AsImage());
                index = Icons.Count ;
                Icons.Add("<Drive>", index);
            }
            else
                index = Icons["<Drive>"];
            return index;
        }
        private int GetFolderImage()
        {
            int index = -1;
            if (!Icons.ContainsKey("<Folder>"))
            {
                Icon i = Shell32.GetFolderIcon(Shell32.IconSize.Small, Shell32.FolderType.Closed);
                imageList1.Images.Add(i.AsImage());
                index = Icons.Count;
                Icons.Add("<Folder>", index);
            }
            else
                index = Icons["<Folder>"];
            return index;
        }
        private int GetFileImage(string path)
        {
            int index = -1;
            string ext = Path.GetExtension(path);

            if (!Icons.ContainsKey(ext))
            {
                Icon i = Shell32.GetFileIcon(path, Shell32.IconSize.Small, true);
                imageList1.Images.Add(i.AsImage());
                index = Icons.Count;
                Icons.Add(ext, index);
            }
            else
                index = Icons[ext];
            return index;
        }

        private void InitFolders(TreeListNode node)
        {
            if (this.InvokeRequired)
            {
                    this.Invoke(new Action<TreeListNode>(this.InitFolders), node);
            }
            else
            {
                try
                {
                    treeList1.LockReloadNodes();
                    string[] dirs = Directory.GetDirectories(node[this.colPath].AsString(), "*", SearchOption.TopDirectoryOnly);
                    {
                        foreach (string d in dirs)
                        {
                            try
                            {
                                TreeListNode n = treeList1.AppendNode(new object[] {d, d.Substring(d.LastIndexOf(Path.DirectorySeparatorChar)).TrimStartEnd('\\'), "<Folder>" }, node);
                                n.Tag = true;
                                n.ImageIndex = GetFolderImage();
                                n.HasChildren = DirHasChildren(d);
                            }
                            catch { }
                        }
                    }
                }
                catch { }
                finally
                {
                    treeList1.UnlockReloadNodes();
                }
            }
        }
        private bool DirHasChildren(string path)
        {
            bool result = false;
            try
            {
                string[] dirs = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
                string[] files = Directory.GetFiles(path, getFileFilter(), SearchOption.TopDirectoryOnly);
                result = (dirs != null && dirs.Length > 0) || (files != null && files.Length >0);
            }
            catch { result = false; }
            return result;
        }
        private void treeList1_BeforeExpand(object sender, DevExpress.XtraTreeList.BeforeExpandEventArgs e)
        {
            if (e.Node.Tag.IsNotNull())
            {
                backgroundWorker1.RunWorkerAsync(e.Node);
                e.Node.Tag = null;
            }
        }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            TreeListNode n = e.Argument as TreeListNode;
            InitFolders(n);
            InitFiles(n);
        }
        private void SelectFile(string file)
        {
            treeList1.Focus();
            if (file.IsNotNull())
            {
                foreach (TreeListNode n in treeList1.Nodes)
                {
                    TreeListNode node = FindNode(n, file);
                    if (node != null)
                    {
                        treeList1.FocusedNode = node;
                        break;
                    }
                }
            }
        }

        private TreeListNode FindNode(TreeListNode node, string path)
        {
            TreeListNode n = null;
            if (node != null)
            {
                if (node[this.colPath].AsString().ToUpper() ==
                    path.ToUpper())
                    return node;
                if (!path.ToUpper().StartsWith(node[this.colPath].AsString().ToUpper()))
                    return null;
                else
                    n = node;
                if (node.Tag.IsNotNull())
                {
                    InitFolders(node);
                    InitFiles(node);
                    node.Tag = null;
                }
                foreach (TreeListNode n1 in node.Nodes)
                {
                    TreeListNode n2 = FindNode(n1, path);
                    if (n2 != null)
                    {
                        n = n2;
                        InitFiles(n);
                        break;
                    }
                }
            }
            return n;
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            if (treeList1.FocusedNode != null)
                if (treeList1.FocusedNode[colExtensions].AsString() != "<Folder>")
                {
                    FileName = treeList1.FocusedNode[colPath].AsString();
                    DialogResult = DialogResult.OK;
                    Close();
                }
        }
        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }
        private void treeList1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Right)
            {
                if (treeList1.FocusedNode != null)
                {
                    if (treeList1.FocusedNode.Tag.IsNotNull())
                    {
                        InitFolders(treeList1.FocusedNode);
                        treeList1.FocusedNode.Tag = null;
                    }
                    treeList1.FocusedNode.Expanded = true;
                    if (treeList1.FocusedNode.HasChildren)
                        treeList1.FocusedNode = treeList1.FocusedNode.FirstNode;
                }
            }
            if (e.KeyCode == Keys.Left)
            {
                if (treeList1.FocusedNode != null)
                {
                    treeList1.FocusedNode = treeList1.FocusedNode.ParentNode;
                    if (treeList1.FocusedNode != null)
                        treeList1.FocusedNode.Expanded = false;
                }
            }
            if (e.KeyCode == Keys.Enter)
            {
                btnOk.PerformClick();
            }
        }

        private void treeList1_CustomDrawNodeImages(object sender, DevExpress.XtraTreeList.CustomDrawNodeImagesEventArgs e)
        {
            if (e.Node[colExtensions].AsString() == "<Drive>")
            {
                e.SelectImageIndex = GetDriveImage(e.Node[colPath].AsString());
            }
            else if (e.Node[colExtensions].AsString() == "<Folder>")
            {
                e.SelectImageIndex = GetFolderImage();
            }
            else
            {
                e.SelectImageIndex = GetFileImage(e.Node[colPath].AsString());
            }
        }

        private void cbMask_SelectedIndexChanged(object sender, EventArgs e)
        {
            foreach (TreeListNode n in treeList1.Nodes)
                ReinitNodes(n);
        }

        private void ReinitNodes(TreeListNode node)
        {
            node.HasChildren = DirHasChildren(node[colPath].AsString());
            foreach (TreeListNode n in node.Nodes)
            {
                InitFiles(n);
                n.HasChildren = DirHasChildren(n[colPath].AsString());
                ReinitNodes(n);
            }

        }

        private void treeList1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (treeList1.FocusedNode != null)
            {
                if(treeList1.FocusedNode[colExtensions].AsString() != "<Drive>" &&
                    treeList1.FocusedNode[colExtensions].AsString() != "<Folder>" )
                    btnOk.PerformClick();
            }
        }
    }
}